package com.pagoda.viewfinder_compiler.model;

import com.pagoda.viewfinder_compiler.TypeUtil;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;

import java.util.LinkedList;
import java.util.List;

import javax.lang.model.element.Modifier;
import javax.lang.model.element.Name;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;

/**
 * E-mail: liaohailong190@foxmail.com
 * Date: 2020/7/16 17:01
 * Description:
 *
 * @author liaohailong
 */
public class ViewFinderClass {

    // class
    private TypeElement classElement;
    // element environment
    private Elements elements;
    // BindView list
    private List<BindViewField> fields;
    // BindClick list
    private List<BindClickMethod> methods;

    public ViewFinderClass(TypeElement classElement, Elements elements) {
        this.classElement = classElement;
        this.elements = elements;
        this.fields = new LinkedList<>();
        this.methods = new LinkedList<>();
    }

    public void addField(BindViewField field) {
        fields.add(field);
    }

    public void addMethod(BindClickMethod method) {
        methods.add(method);
    }

    public String getFullClassName() {
        return classElement.getQualifiedName().toString();
    }

    public JavaFile generateFinder() {
        /*
         * 第一步:
         * 创建inject函数
         * com.pagoda.viewfinder_bridge.Finder<HOST>
         * void inject(HOST host, IProvider<?> provider);
         * */
        MethodSpec.Builder injectBuilder = MethodSpec.methodBuilder("inject")
                .addModifiers(Modifier.PUBLIC)
                .addAnnotation(Override.class)
                .returns(TypeName.VOID)
                .addParameter(TypeName.get(classElement.asType()), "host", Modifier.FINAL)
                .addParameter(TypeUtil.PROVIDER, "provider");

        /*
         * 第二步：
         * 添加findViewById函数
         * host.fieldName = (type)(provider.findView(id))
         * */
        for (BindViewField field : fields) {
            Name fieldName = field.getFieldName();
            TypeName typeName = ClassName.get(field.getFieldType());
            int resId = field.getResId();
            injectBuilder.addStatement("host.$N=($T)(provider.findView($L))", fieldName, typeName, resId);
        }

        /*
         * 第三步:
         * 声明View.OnClickListener listener;
         * 创建View.OnClickListener对象
         * 设置listener
         * provider.findView(id).setOnClickListener(listener)
         * */
        if (methods.size() > 0) {
            injectBuilder.addStatement("$T listener", TypeUtil.ANDROID_ON_CLICK_LISTENER);
        }
        for (BindClickMethod method : methods) {
            MethodSpec onClickMethod = MethodSpec.methodBuilder("onClick")
                    .addAnnotation(Override.class)
                    .addModifiers(Modifier.PUBLIC)
                    .returns(TypeName.VOID)
                    .addParameter(TypeUtil.ANDROID_VIEW, "view")
                    .addStatement("host.$N(view)", method.getMethodName())
                    .build();

            TypeSpec listener = TypeSpec.anonymousClassBuilder("")
                    .addSuperinterface(TypeUtil.ANDROID_ON_CLICK_LISTENER)
                    .addMethod(onClickMethod)
                    .build();
            injectBuilder.addStatement("listener = $L", listener);

            for (int id : method.getIds()) {
                injectBuilder.addStatement("provider.findView($L).setOnClickListener(listener)", id);
            }
        }

        /*
         * 生成unbind函数
         * com.pagoda.viewfinder_bridge.Finder<HOST, SOURCE>
         * void unbind(HOST host, IProvider<?> provider);
         * */
        MethodSpec.Builder unbindBuilder = MethodSpec.methodBuilder("unbind")
                .addAnnotation(Override.class)
                .addModifiers(Modifier.PUBLIC)
                .returns(TypeName.VOID)
                .addParameter(TypeName.get(classElement.asType()), "host", Modifier.FINAL)
                .addParameter(TypeUtil.PROVIDER, "provider");

        for (BindViewField field : fields) {
            unbindBuilder.addStatement("host.$N=null", field.getFieldName());
        }
        for (BindClickMethod method : methods) {
            int[] ids = method.getIds();
            for (int id : ids) {
                unbindBuilder.addStatement("provider.findView($L).setOnClickListener(null)", id);
            }
        }

        /*
         * 最后一部:
         * 创建XXX$$Finder
         * */
        TypeName hostType = TypeName.get(classElement.asType());
        ParameterizedTypeName clz = ParameterizedTypeName.get(TypeUtil.FINDER, hostType);
        TypeSpec finderClz = TypeSpec.classBuilder(classElement.getSimpleName() + "$$Finder")
                .addModifiers(Modifier.PUBLIC)
                .addSuperinterface(clz)
                .addMethod(injectBuilder.build())
                .addMethod(unbindBuilder.build())
                .build();
        String packageName = elements.getPackageOf(classElement).getQualifiedName().toString();
        return JavaFile.builder(packageName, finderClz).build();
    }
}
